package com.sunrise.gateway.commons;

import com.google.common.base.Charsets;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public abstract class WechatAuthorizationUtils {
    private final static Logger logger = LoggerFactory.getLogger(WechatAuthorizationUtils.class);

    // 如果不包含相同key和value的cookie, 则添加
    public static boolean addCookieIfNotExist(HttpServletRequest req, HttpServletResponse resp, String cookieName, String cookieValue) {
        Cookie[] preCookies = req.getCookies();
        if (null != preCookies) {
            for (Cookie preCookie : preCookies) {
                if (cookieName.equals(preCookie.getName()) && cookieValue.equals(preCookie.getValue())) {
                    return false;
                }
            }
        }

        Cookie cookie = new Cookie(cookieName, cookieValue);
        cookie.setPath("/");
        resp.addCookie(cookie);
        return true;
    }

    // 如果当前域名不在redirectUri, 则使用当前参数, 跳转到redirectUri所在的域名
    public static boolean redirectToCurrentHostIfNotSame(HttpServletRequest req, HttpServletResponse resp, String redirectUri) throws IOException {
        String protocol;
        if (redirectUri.startsWith("http://"))
            protocol = "http://";
        else if (redirectUri.startsWith("https://"))
            protocol = "https://";
        else
            return false;

        String stateWithoutProtocol = redirectUri.substring(protocol.length());
        int hostEndIdx = stateWithoutProtocol.indexOf('/');
        if (hostEndIdx < 0) {
            hostEndIdx = stateWithoutProtocol.indexOf('?');
            if (hostEndIdx < 0) {
                hostEndIdx = stateWithoutProtocol.length();
            }
        }
        String hostWithPort = stateWithoutProtocol.substring(0, hostEndIdx);
        int colonIdx = hostWithPort.indexOf(':');
        String hostWithoutPort;
        if (colonIdx >= 0)
            hostWithoutPort = hostWithPort.substring(0, colonIdx);
        else
            hostWithoutPort = hostWithPort;

        if (hostWithoutPort.equals(req.getHeader("Host")))
            return false;

        String url = protocol + hostWithPort + req.getRequestURI() + "?" + req.getQueryString();
        if (logger.isDebugEnabled()) {
            logger.debug("current host = {}, state's hostWithoutPort = {}, redirect to url {}", req.getHeader("Host"), hostWithoutPort, url);
        }
        resp.sendRedirect(url);
        return true;
    }


    public static class WechatAuthInfo {
        public String redirectUri;
        public String code;
        public String appId;
        public WechatAuthInfo(String redirectUri, String code, String appId) {
            this.redirectUri = redirectUri;
            this.code = code;
            this.appId = appId;
        }
    }
    /**
     * redirect_uri 格式为
     * http://www.shangyuan.cn/sunrise-gateway-b2c/#/shop/4444?fff=aaa
     * 只需要关注  第一个? 后
     * */
    public static WechatAuthInfo getWechatAuthInfo(HttpServletRequest req, HttpServletResponse resp) {
        String redirectUri = null;

        try {
            // 获取参数
            String redirectUriHex = req.getParameter("redirect_uri");
            if (StringUtils.isEmpty(redirectUriHex)) {
                return null;
            }
            byte[] redirectUriBytes = Hex.decodeHex(redirectUriHex.toCharArray());
            redirectUri = new String(redirectUriBytes, Charsets.UTF_8);

            String code = req.getParameter("code");
            if (StringUtils.isEmpty(code)) {
                throw new Exception("code is empty");
            }

            // 重定向
            if (redirectToCurrentHostIfNotSame(req, resp, redirectUri)) {
                return null;
            }

            // 从重定向链接中获取appId
            int questionIdx = redirectUri.indexOf('?');
            if (questionIdx < 0) {
                throw new Exception("cannot get appId, state=" + redirectUri);
            }
            String stateParamsStr = redirectUri.substring(questionIdx + 1);
            String[] stateParamsArray = stateParamsStr.split("&");
            String appId = null;
            for (String stateParam : stateParamsArray) {
                if (stateParam.startsWith("appId=")) {
                    appId = stateParam.substring("appId=".length());
                    appId = leaveOutAppIdInvalidChars(appId);
                    break;
                }
            }
            if (StringUtils.isEmpty(appId)) {
                throw new Exception("appId is empty, state=" + redirectUri);
            }

            return new WechatAuthInfo(redirectUri, code, appId);
        } catch (Exception e) {
            logger.info("", e);
            if (!StringUtils.isEmpty(redirectUri)) {
                try {
                    resp.sendRedirect(redirectUri);
                } catch (IOException e1) {
                    logger.info("", e1);
                }
            }
            return null;
        }
    }

    private static String leaveOutAppIdInvalidChars(String appId) {
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<appId.length(); ++i) {
            char ch = appId.charAt(i);
            if ('0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') {
                sb.append(ch);
            } else {
                break;
            }
        }
        return sb.toString();
    }

}
